//
//  NSObject+ZXRuntime.m
//  CollagePicture
//
//  Created by simon on 16/11/17.
//  Copyright © 2016年 simon. All rights reserved.
//

#import "NSObject+ZXRuntime.h"

@implementation NSObject (ZXRuntime)

#pragma mark -交换二个方法的IMP

+ (void)zx_exchangeInstanceMethodWithOriginalSelector:(SEL)originalSel
                                     swizzledSelector:(SEL)swizzledSel
{
    if (originalSel == swizzledSel) {
        return;
    }
    Class cls = self.class;
    //如果没有方法实现，则返回nil；是本类，也可能是父类的方法。
    Method originalMethod = class_getInstanceMethod(cls, originalSel);
    //本类的方法
    Method swizzledMethod = class_getInstanceMethod(cls, swizzledSel);
    if (!swizzledMethod || !originalMethod) {
        return;
    }
    [self swizzleMethodWithOriginalSelector:originalSel originalMethod:originalMethod swizzledSelector:swizzledSel swizzledMethod:swizzledMethod class:cls];
}


+ (void)zx_exchangeClassMethodWithOriginalSelector:(SEL)originalSel
                                  swizzledSelector:(SEL)swizzledSel
{
    Class cls = objc_getMetaClass(class_getName(self.class));
    Method originalMethod = class_getClassMethod(cls, originalSel);
    Method swizzledMethod = class_getClassMethod(cls, swizzledSel);
    [self swizzleMethodWithOriginalSelector:originalSel originalMethod:originalMethod swizzledSelector:swizzledSel swizzledMethod:swizzledMethod class:cls];
}


+ (void)swizzleMethodWithOriginalSelector:(SEL)originalSel
                           originalMethod:(Method)originalMethod
                         swizzledSelector:(SEL)swizzledSel
                           swizzledMethod:(Method)swizzledMethod
                                    class:(Class)cls {
    BOOL didAddMethod = class_addMethod(cls, originalSel, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod));
    if (didAddMethod)
    {
        class_replaceMethod(cls, swizzledSel, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
    }
    else
    {
        method_exchangeImplementations(originalMethod, swizzledMethod);
    }
}


+ (void)getInstanceMethodListWithLog:(BOOL)log block:(void(^)(SEL sel))block{
    Class cls = self.class;
    u_int count;
    Method *methods = class_copyMethodList(cls, &count);
    for (int i = 0; i < count; i++)
    {
        SEL name = method_getName(methods[i]);
        if (log) {
            const char *selName= sel_getName(name);
            NSString *strName = [NSString stringWithCString:selName encoding:NSUTF8StringEncoding];
            NSLog(@"%@ 实例方法:%@",NSStringFromClass(cls),strName);
        }
        if (block) {
            block(name);
        }
        //这2句等同于NSStringFromSelector(name);
    }
    free(methods);
//    NSLog(@"%u",count);
}

///  实例方法-类，类方法-元类Class metaClass = objc_getMetaClass(class_getName(cls));
+ (void)getClassMethodListWithLog:(BOOL)log block:(void(^)(SEL sel))block{
    Class cls = objc_getMetaClass(class_getName(self.class));
    u_int count;
    Method *methods = class_copyMethodList(cls, &count);
    for (int i = 0; i < count; i++)
    {
        SEL name = method_getName(methods[i]);
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-variable"
        if (log) {
            const char *selName= sel_getName(name);
            NSString *strName = [NSString stringWithCString:selName encoding:NSUTF8StringEncoding];
            NSLog(@"%@ 类方法:%@",NSStringFromClass(cls),strName);
        }
#pragma clang diagnostic pop
        if (block) {
            block(name);
        }
    }
    free(methods);
}


+ (void)getClassIvarListWithBlock:(void(^)(Ivar ivar))block{
    Class cls = self.class;
    u_int count = 0;
    Ivar *ivars = class_copyIvarList(cls, &count);
    for (int i = 0; i < count; i++)
    {
        Ivar ivar = ivars[i];
        const char *ivarName = ivar_getName(ivar);
        NSString *strName = [NSString stringWithCString:ivarName encoding:NSUTF8StringEncoding];
        const char *type = ivar_getTypeEncoding(ivar);
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-variable"
        NSLog(@"%@:%s",strName,type);
#pragma clang diagnostic pop
        if (block) {
            block(ivar);
        }
    }
    free(ivars);
//    NSLog(@"%u",count);
}


+ (void)getClassPropertyListWithBlock:(void(^)(objc_property_t property))block{
    Class cls = self.class;
    u_int count = 0;
    objc_property_t *properties = class_copyPropertyList(cls, &count);
    for (int i = 0; i < count; i++)
    {
        objc_property_t property = properties[i];
        const char *propertyName = property_getName(property);
        NSString *strName = [NSString stringWithCString:propertyName encoding:NSUTF8StringEncoding];
        const char *attributes = property_getAttributes(property);
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-variable"
        NSLog(@"%@:%s",strName,attributes);
#pragma clang diagnostic pop
        if (block) {
            block(property);
        }
    }
    free(properties);
//    NSLog(@"%u",count);
}


@end

